home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / Developer Documentation / Recipes, Tech Notes & Articles / Tech Notes / Utilities Documentation / ODDebug Documentation < prev    next >
Encoding:
Text File  |  1995-11-07  |  9.1 KB  |  95 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3.  
  4. ODDebug: Utilities For Debugging
  5. 10 October 1995
  6.  
  7.  
  8. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
  10. Mac and OpenDoc are trademarks of Apple Computer, Inc. 
  11. System Object Model, SOM and SOMobjects are trademarks of the IBM Corporation in the United States and other countries.
  12.  
  13. The ODDebug utility contains a set of macros and functions that you can use in your code to help verify that it's behaving correctly: these include warnings, assertions and safe type-casts. By doing so, you can be notified (via a timely user break into your debugger) when something starts to go wrong, instead of later on when the problem leads to a crash or incorrect operation.
  14.  
  15. These utilities use a global flag called ODDebug. This is a preprocessor symbol/macro that must be pre-defined (it's usually #defined at the start of a precompiled header or prefix file) as 0 or 1. When it is 1, all of the debugging utilities are in effect. They will make your code slightly bigger and slower, but easier to debug since you'll be notified early of potential problems. When ODDebug is 0, none of the debugging utilities generate any extra code or have any effect on your part's operation. Therefore, you should define ODDebug as 1 while you are developing and testing your part, and define it as 0 in the final build that you ship. (In particular, it's dangerous to give a debug build to end users who do not have MacsBug or a comparable low-level debugger installed, since the user breaks caused by WARNs or ASSERTs will simply cause a system error.)
  16.  
  17. You can (and should) use these utilities liberally in your code wherever you want to make sure that certain conditions are true, or at a point where something may have gone wrong. They make your code much easier to debug without affecting the size or speed of your shipping product.
  18.  
  19. Development System Issues
  20.  
  21. • To use the ODDebug utility you must of course add the source file to your project or makefile.
  22. • Less obvious is that ODDebug calls ANSI routines such as stdio, which in the CodeWarrior development environment means that you must also add the file console.stubs.c to your project or face link errors. You can find this file in the “MacOS Support: Libraries: SIOUX:” folder in the CodeWarrior folder.
  23.  
  24. Warnings
  25.  
  26. WARN( message, [parameter]* );
  27.  
  28. The WARN macro displays a formatted message in the debugger (your high-level debugger such as Symantec's or Metrowerks' if it's targeted the document's process, otherwise MacsBug or a comparable low-level debugger.) WARN takes exactly the same parameters as the standard ANSI function printf( ). The message string (a C string) is required. It may contain placeholders that begin with the "%" character, each of which requires a matching extra parameter that provides its value. (Consult your development system's documentation or any book on C programming for full details on printf.)
  29. Like all the ODDebug utilities, WARN generates absolutely no code at all if ODDebug is defined to be 0.
  30.  
  31. Example:
  32.     for( long i=0; i<nElements; i++ )
  33.         if( arr[i]==value ) return i;
  34.     WARN("Could not find value %d in arr!", value);
  35.     return -1;
  36.  
  37. Assertions
  38.  
  39. ASSERT( condition, error );
  40. WASSERT( condition );
  41. ASSERTM( condition, error, message );
  42. WASSERTM( condition, message );
  43.  
  44. Assertions are used to verify that a particular condition is true, typically something that must be true in order for things to work as expected. For instance, a function might assert that an input parameter is not negative (this is called a precondition) or that the value it is about to return is not NULL (this is a postcondition). A method might assert that an instance variable of the object is not NULL (a validity check.)
  45.  
  46. ASSERT takes a Boolean condition and an error code. If the condition is false, it will display a message in the debugger, and then THROW that error code (see the documentation on exception handling for the details of THROW.) Typical error codes used in assertions are kODErrAssertionFailed or kODErrorIllegalNullParameter.
  47. The message in the debugger looks like "condition ...NOT! at function-name" where condition is the condition that failed and function-name is the name of the function (or source file if MacsBug/traceback symbols are not available) that contained the ASSERT call.
  48.  
  49. Example:
  50.     void ClearElement( long arr[], long nElements, long value ) {
  51.         for( long i=0; i<nElements; i++ )
  52.             if( arr[i]==value ) break;
  53.         ASSERT(i<nElements, kODErrAssertionFailed);
  54.         arr[i] = 0;
  55.     }
  56.  
  57. If the array 'arr' does not contain any element whose value is 'value', in the debug build of the program you will get a user break that reads:
  58.     i<nElements ... NOT! At NukeElement+42
  59.  
  60. WASSERT (Warning ASSERT) is just like ASSERT but does not throw an exception. It's intended to be used in cases where the problem is not serious enough to justify aborting the current operation; it's sufficient to notify that something is wrong and then continue.
  61.  
  62. ASSERTM (ASSERT Message) is just like ASSERT but lets you add a custom string to appear in the debugger in addition to the text of the condition. This is handy if the condition itself (e.g. "j != 0") isn't terribly informative by itself. (Unfortunately the message cannot be parametrized as the message in WARN can be.)
  63.  
  64. WASSERTM (Warning ASSERT Message) is — you guessed it — just a combination of WASSERT and ASSERTM. It takes a custom message and does not throw an exception.
  65.  
  66. An Important Warning: Assertions should only be used to test for conditions that should be impossible to occur in the shipping product. An assertion provides a certain safety net in the debug version of the program in that it will abort a procedure if something goes wrong. But it doesn't do anything in the shipping product. Things that could go wrong in the shipping product need to have explicit tests and exceptions that don't get removed in the final compile. For instance, this is an unfortunate mistake:
  67.     Handle h = GetResource('fooo',128);
  68.     ASSERT(f!=kODNULL,kODErrOutOfMemory);
  69.     HLock(h);
  70. The problem here is that, in the shipping product, the ASSERT doesn't exist, and if the 'fooo' resource can't be loaded, NULL will be passed to HLock, probably causing a crash or heap corruption. The test here is too important to be left out of the final product; what was really needed was something like:
  71.     if( !h ) THROW( ResError() ?ResError() :resNotFound );
  72.  
  73. PRINT
  74.  
  75. Even in these days of symbolic debuggers, sometimes the best debugging tool is still the humble PRINT statement. Complex algorithms can sometimes only be debugged by making them spew out a log of everything they do, and complex data structures sometimes need custom code to display them in all their glory.
  76.  
  77. System Object Model™ (SOM) provides a somPrintf( ) function that acts like printf. The output is sent to OpenDoc. In a nondebug build the output is thrown away, but in a debug build the ODDebug menu (just below the About... command) contains commands to redirect the output to the low-level debugger, to a text file, or to the freeware DebugWindow application. (See the documentation for the debug build of OpenDoc for more details.)
  78.  
  79. The PRINT macro is exactly like somPrintf, except that it does not generate any code in a nondebug build. This is generally the behavior you want since somPrintf will never be of use to end users.
  80.  
  81. Since you can generate reams of output using PRINT, it can sometimes be annoying to leave it on, even in a debug build of your part. That's what the LOG macro is for. It is just like PRINT but is normally disabled, even in a nondebug build. To enable it, you have to #define the symbol LOGGING to be 1. To do this, add these lines (probably at the top of your source file):
  82.     #undef LOGGING
  83.     #define LOGGING 1
  84. (You have to undefine the previous value, which is 0, or the compiler may complain.) That #define statement then toggles the behavior of all the LOG statements in the source file. When you don't need them, just change the value to 0.
  85.  
  86. Safe Type-Casting
  87.  
  88. A frequent source of runtime crashes is type-casting a pointer to an incorrect type. C++ being only semi-object-oriented, there are times when you need to type-cast (typically to cast a variable to a subclass of the base class it is declared as.) Since SOM objects provide run-time information about their classes, we can provide a utility that will do this potentially unsafe cast and check at run-time whether it actually is safe or not. If it isn't, you'll get a warning.
  89.  
  90. CAST( pointer, class )
  91. Casts the value pointer — which must be a pointer to some SOM object — to a pointer to the class class. The return value has the same value as pointer but is of the type class*. Before returning, CAST makes sure that the object is actually of the class class or one of its subclasses. If not, you get a warning. Like all these other utilities, this check is disabled in a non-debug build, so you get a regular C++ typecast that doesn't generate any extra code.
  92.  
  93. Internal Stuff
  94.  
  95. Do not call the function ODInitExceptions. This is for internal use by OpenDoc only, and probably shouldn't even be exposed in this utility. Kindly ignore it. Thanks.